﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.ComponentModel;
using TR0217.ControlEx.Properties;

namespace TR0217.ControlEx
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(CollapsiblePanel), "CollapsiblePanel.bmp")]
    public class CollapsiblePanel : Panel
    {
        #region Properties
        #region Appearance
        private Color _outlineColor = Color.White;
        public System.Drawing.Color OutlineColor
        {
            get { return _outlineColor; }
            set
            {
                _outlineColor = value;
                this.Invalidate();
            }
        }

        public int _outlineWidth = 1;

        public int OutlineWidth
        {
            get { return _outlineWidth; }
            set 
            { 
                _outlineWidth = value;
                //Padding padding = new Padding();
                //padding = base.Padding;
                //padding.Left = padding.Left < _outlineWidth ? _outlineWidth : padding.Left;
                //padding.Right = padding.Right < _outlineWidth ? _outlineWidth : padding.Right;
                //padding.Bottom = padding.Bottom < _outlineWidth ? _outlineWidth : padding.Bottom;
                //padding.Top = padding.Top < (_outlineWidth + _captionHeight) ? (_outlineWidth + _captionHeight) : padding.Top;
                //this.Padding = padding;
                this.Invalidate();
            }
        }

        public new BorderStyle BorderStyle
        {
            get { return base.BorderStyle; }
        }

        private int _captionHeight = 20;
        public int CaptionHeight
        {
            get { return _captionHeight; }
            set 
            { 
                _captionHeight = value;
                //Padding padding = new Padding();
                //padding = base.Padding;
                //padding.Top = padding.Top < (_outlineWidth + _captionHeight) ? (_outlineWidth + _captionHeight) : padding.Top;
                //this.Padding = padding;
                this.Invalidate();
            }
        }

        //public new Padding Padding
        //{
        //    get { return base.Padding; }
        //    set 
        //    {
        //        Padding padding = new Padding();
        //        padding = value;
        //        padding.Left = padding.Left < _outlineWidth ? _outlineWidth : padding.Left;
        //        padding.Right = padding.Right < _outlineWidth ? _outlineWidth : padding.Right;
        //        padding.Bottom = padding.Bottom < _outlineWidth ? _outlineWidth : padding.Bottom;
        //        padding.Top = padding.Top < (_outlineWidth + _captionHeight) ? (_outlineWidth + _captionHeight) : padding.Top;
        //        this.Padding = padding;
        //    }
        //}
        private int _radius = 5;
        public int Radius
        {
            get { return _radius; }
            set
            {
                _radius = value;
                this.Invalidate();
            }
        }

        private Color _captionBeginColor = Color.FromArgb(225,238,255);
        private Color _captionEndColor = Color.FromArgb(83,128,209);
        private LinearGradientMode _captionGradientMode = LinearGradientMode.Horizontal;
        [Description("Get the caption gradient's start color."), Category("Caption"), Browsable(true)]
        public Color CaptionBeginColor
        {
            get { return _captionBeginColor; }
            set
            {
                _captionBeginColor = value;
                this.Invalidate();
            }
        }

        [Description("Get the caption gradient's end color."), Category("Caption"), Browsable(true)]
        public Color CaptionEndColor
        {
            get { return _captionEndColor; }
            set
            {
                _captionEndColor = value;
                this.Invalidate();
            }
        }

        [Description("Change the caption gradient direction."), Category("Caption"), Browsable(true)]
        public LinearGradientMode CaptionGradientMode
        {
            get { return _captionGradientMode; }
            set
            {
                _captionGradientMode = value;
                this.Invalidate();
            }
        }

        [Browsable(true)]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        private bool _gradientClinet = false;
        private Color _clientBeginColor = Color.FromArgb(225,238,255);
        private Color _clientEndColor = Color.FromArgb(83,128,209);
        private LinearGradientMode _clientGradientMode = LinearGradientMode.Vertical;

        [Description("whether to paint the client with gradient color."), Category("Client"), Browsable(true)]
        public bool GradientClinet
        {
            get { return _gradientClinet; }
            set { _gradientClinet = value; }
        }

        [Description("Get the client gradient's start color."), Category("Client"), Browsable(true)]
        public Color ClientBeginColor
        {
            get { return _clientBeginColor; }
            set
            {
                _clientBeginColor = value;
                this.Invalidate();
            }
        }

        [Description("Get the client gradient's end color."), Category("Client"), Browsable(true)]
        public Color ClientEndColor
        {
            get { return _clientEndColor; }
            set
            {
                _clientEndColor = value;
                this.Invalidate();
            }
        }

        [Description("Change the client gradient direction."), Category("Client"), Browsable(true)]
        public LinearGradientMode ClientGradientMode
        {
            get { return _clientGradientMode; }
            set
            {
                _clientGradientMode = value;
                this.Invalidate();
            }
        }
        #endregion
        #region Collapsible
        public EventHandler CollapsedChanged;
        private bool _collapsed;
        private bool _collapsible = true;

        /// <summary>
        /// Indicates whether the component can collapsed.
        /// </summary>
        [Browsable(true)]
        public bool Collapsible
        {
            get { return _collapsible; }
            set { _collapsible = value; }
        }

        /// <summary>
        /// Indicates whether the component is collapsed.
        /// </summary>
        [Browsable(true)]
        public bool Collapsed
        {
            get { return _collapsed; }
            set
            {
                if (_collapsed != value)
                {
                    this.Collapse(value);
                    if (this.CollapsedChanged != null)
                        this.CollapsedChanged(this, new EventArgs());
                }
            }
        }

        private int _originalHeight;
        /// <summary>
        /// Collapse or expend the pane
        /// </summary>
        /// <param name="_collapsed">true for collapse, false for expend</param>
        public void Collapse(bool collapsed)
        {
            if (!_collapsible) return;

            if (collapsed && !_collapsed)
            {
                _originalHeight = Height;
                this.Height = _captionHeight;
                _collapsed = true;
            }
            else if (!collapsed && _collapsed)
            {
                this.Height = _originalHeight;
                _collapsed = false;
            }
        }
        #endregion
        #endregion

        public CollapsiblePanel()
        {
            SetStyle(
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.ResizeRedraw, true);
            this.UpdateStyles();
            base.BorderStyle = BorderStyle.None;
            base.Text = base.Name;
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (_gradientClinet && base.BackgroundImage == null)
            {
                if (this.BackColor == Color.Transparent)
                {
                    base.OnPaintBackground(e);
                }
                if (this.Height > 0 && this.Width > 0)
                {
                    Rectangle rect = new Rectangle(0, _captionHeight, this.Width, this.Height-_captionHeight);
                    Brush brush = new LinearGradientBrush(rect,
                        _clientBeginColor, _clientEndColor, _clientGradientMode);
                    e.Graphics.FillRectangle(brush, rect);
                    brush.Dispose();
                }
            }
            else
            {
                base.OnPaintBackground(e);
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (_captionHeight > 0)
            {
                Rectangle rect = new Rectangle(0, 0,
                    this.Width, _captionHeight);
                if (rect.Width > 0)
                {
                    GraphicsPath shape = new GraphicsPath();
                    shape.AddArc(-1, -1, _radius * 2, _radius * 2, 180, 90);
                    shape.AddLine(_radius, 0, rect.Right - _radius, 0);
                    shape.AddArc(rect.Right - _radius * 2, -1, _radius * 2, _radius * 2, 270, 90);
                    shape.AddLines(new Point[] {
                        new Point(rect.Right,_radius),
                        new Point(rect.Right,rect.Bottom),
                        new Point(rect.Left,rect.Bottom),
                        new Point(rect.Left,_radius)});
                    Region r = new Region(shape);
                    Brush brush = new LinearGradientBrush(rect,
                        _captionBeginColor, _captionEndColor, _captionGradientMode);
                    e.Graphics.FillRegion(brush, r);
                    brush.Dispose();
                    r.Dispose();
                    shape.Dispose();
                    SizeF s = e.Graphics.MeasureString(base.Text, this.Font);
                    RectangleF rectf = new RectangleF(_outlineWidth + 3, _outlineWidth + rect.Height - s.Height, rect.Width-23, rect.Height);
                    if (rectf.Width>0&&rect.Height>0)
                    {
                        Brush tb = new SolidBrush(base.ForeColor);
                        e.Graphics.DrawString(base.Text, this.Font, tb, rectf);
                        tb.Dispose();
                        if (_collapsible)
                        {
                            Bitmap bitmap = _collapsed ? Resources.collapsed : Resources.expended;
                            int x = this.Width - bitmap.Width - _outlineWidth - 7;
                            int y = (_captionHeight - bitmap.Height) / 2 + _outlineWidth;
                            int width = rect.Left - x;
                            int height = rect.Bottom - y;

                            e.Graphics.DrawImageUnscaled(bitmap, x, y, width, height);
                        }   
                    }
                }
            }
            if (_captionHeight > -1 &&_outlineWidth > 0)
            {
                Pen pen = new Pen(_outlineColor, _outlineWidth);
                pen.Alignment = PenAlignment.Inset;
                e.Graphics.DrawRectangle(pen, 0, _captionHeight, this.Width - 1, this.Height - _captionHeight-1);
                pen.Dispose();
            }
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            Rectangle rect = new Rectangle(_outlineWidth, _outlineWidth,
                    this.Width - _outlineWidth - _outlineWidth, _captionHeight);
            if (rect.Contains(e.Location))
            {
                this.Collapse(!_collapsed);
            }
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0014) // 禁掉清除背景消息
                return;

            base.WndProc(ref m);
        }
    }
}
